Skip to content

Compilation fails with Literal of type double cannot be implicitly converted. #2708

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
redknightlois opened this issue Mar 13, 2025 · 4 comments

Comments

@redknightlois
Copy link
Contributor

After updating to the latest .Net 9.0 SDK and updating Visual Studio we started having issues compiling the solutions. Since we had similar issues on our codebase, maybe it is related to the changes in overload resolution.

S:\Src\ravendb-60-git\bench\Micro.Benchmark\bin\Release\net9.0\e60f7001-ab2b-4959-8145-809b29eb272a\e60f7001-ab2b-4959-8145-809b29eb272a.notcs(17761,69): error CS0664: Literal of type double cannot be implicitly converted to type 'float'; use an 'F' suffix to create a literal of this type [S:\Src\ravendb-60-git\bench\Micro.Benchmark\bin\Release\net9.0\e60f7001-ab2b-4959-8145-809b29eb272a\BenchmarkDotNet.Autogenerated.csproj]
S:\Src\ravendb-60-git\bench\Micro.Benchmark\bin\Release\net9.0\e60f7001-ab2b-4959-8145-809b29eb272a\e60f7001-ab2b-4959-8145-809b29eb272a.notcs(16375,67): error CS0664: Literal of type double cannot be implicitly converted to type 'float'; use an 'F' suffix to create a literal of this type [S:\Src\ravendb-60-git\bench\Micro.Benchmark\bin\Release\net9.0\e60f7001-ab2b-4959-8145-809b29eb272a\BenchmarkDotNet.Autogenerated.csproj]
S:\Src\ravendb-60-git\bench\Micro.Benchmark\bin\Release\net9.0\e60f7001-ab2b-4959-8145-809b29eb272a\e60f7001-ab2b-4959-8145-809b29eb272a.notcs(17167,69): error CS0664: Literal of type double cannot be implicitly converted to type 'float'; use an 'F' suffix to create a literal of this type [S:\Src\ravendb-60-git\bench\Micro.Benchmark\bin\Release\net9.0\e60f7001-ab2b-4959-8145-809b29eb272a\BenchmarkDotNet.Autogenerated.csproj]
S:\Src\ravendb-60-git\bench\Micro.Benchmark\bin\Release\net9.0\e60f7001-ab2b-4959-8145-809b29eb272a\e60f7001-ab2b-4959-8145-809b29eb272a.notcs(16573,67): error CS0664: Literal of type double cannot be implicitly converted to type 'float'; use an 'F' suffix to create a literal of this type [S:\Src\ravendb-60-git\bench\Micro.Benchmark\bin\Release\net9.0\e60f7001-ab2b-4959-8145-809b29eb272a\BenchmarkDotNet.Autogenerated.csproj]

You can inspect the attached file.
c926cbed-3cb6-4e22-80b1-08aa98602f89.zip

@timcassell
Copy link
Collaborator

Can you please share your benchmark that caused this failure? Micro.Benchmark.Benchmarks.Parsing.FindEscapePositions

@redknightlois
Copy link
Contributor Author

redknightlois commented Mar 14, 2025

Sure. This is the benchmark

using System;
using System.Linq;
using BenchmarkDotNet.Analysers;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Validators;


namespace Micro.Benchmark.Benchmarks.Parsing
{
    //[HardwareCounters(HardwareCounter.CacheMisses, HardwareCounter.TotalIssues, HardwareCounter.BranchMispredictions, HardwareCounter.InstructionRetired )]
    [DisassemblyDiagnoser]
    [Config(typeof(FindEscapePositions.Config))]
    public unsafe class FindEscapePositions
    {
        private class Config : ManualConfig
        {
            public Config()
            {
                AddJob(new Job(RunMode.Default)
                {
                    Environment =
                    {
                        Runtime = CoreRuntime.Core90, 
                        Platform = Platform.X64, 
                        Jit = Jit.RyuJit
                    }
                });

                AddExporter(GetExporters().ToArray());

                AddValidator(BaselineValidator.FailOnError);
                AddValidator(JitOptimizationsValidator.FailOnError);

                AddAnalyser(EnvironmentAnalyser.Default);
            }
        }

        private const int MaxSize = 4096 * 64;

        [Params(7, 16, 127, 128, 255, 256, 4096, MaxSize)]
        public int Length { get; set; }

        [Params(0.0, 0.05, 0.1, 0.5, 0.99, 1.0)]
        public float NonAsciiProbability { get; set; }

        public const int Operations = 100;

        private readonly char[] _source = new char[MaxSize];

        [GlobalSetup]
        public void Setup()
        {
            var r = new Random();
            for (int i = 0; i < MaxSize; i++)
            {
                if (r.NextSingle() < NonAsciiProbability)
                {
                    _source[i] = (char)(r.Next(char.MaxValue - 256) + 256);
                }
                else
                {
                    _source[i] = (char)r.Next(255);
                }
            }
        }

        [Benchmark(Baseline = true)]
        public int Reference()
        {
            var count = 0;
            var controlCount = 0;

            for (int i = 0; i < _source.Length; i++)
            {
                var value = _source[i];

                // PERF: We use the values directly because it is 5x faster than iterating over a constant array.
                // 8  => '\b' => 0000 1000
                // 9  => '\t' => 0000 1001
                // 10 => '\n' => 0000 1010

                // 12 => '\f' => 0000 1100
                // 13 => '\r' => 0000 1101

                // 34 => '"'  => 0010 0010
                // 92 => '\\' => 0101 1100

                if (value == 92 || value == 34 || (value >= 8 && value <= 13 && value != 11))
                {
                    count++;
                    continue;
                }

                if (value < 32)
                {
                    controlCount++;
                }
            }

            // we take 5 because that is the max number of bytes for variable size int
            // plus 1 for the actual number of positions

            // NOTE: this is used by FindEscapePositionsIn, change only if you also modify FindEscapePositionsIn
            return (count + 1) * 5 + controlCount * 5;
        }


        private static ReadOnlySpan<int> EscapePositionsCountTable =>
        [
            0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
        ];

        private static ReadOnlySpan<int> EscapePositionsControlTable =>
        [
            1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1,
            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
        ];

        [Benchmark]
        public int TableBased()
        {
            var count = 0;
            var controlCount = 0;

            foreach (var value in _source)
            {
                if (value >= byte.MaxValue)
                    continue;

                count += EscapePositionsCountTable[value];
                controlCount += EscapePositionsControlTable[value];
            }

            // we take 5 because that is the max number of bytes for variable size int
            // plus 1 for the actual number of positions

            // NOTE: this is used by FindEscapePositionsIn, change only if you also modify FindEscapePositionsIn
            return (count + 1) * 5 + controlCount * 5;
        }
    }
}

@timcassell
Copy link
Collaborator

Does it work if you change it like this?

-       [Params(0.0, 0.05, 0.1, 0.5, 0.99, 1.0)]
+       [Params(0.0f, 0.05f, 0.1f, 0.5f, 0.99f, 1.0f)]
        public float NonAsciiProbability { get; set; }

@redknightlois
Copy link
Contributor Author

I have been looking on the code before reading this, and yes that works. I was going to workaround it by just converting to double instead.

            instance.Length = 262144;instance.NonAsciiProbability = 0.05d;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants